/*
 *  $Id: Union.cs 1233 2010-12-18 17:54:48Z thenn.erannor $
 *  This file is a part of Ragima CCG.
 *  (C) 2008-2010 Ragima development group.
 *
 *  Licensed under the terms of the GNU GPL License version 2.
 *
 */

using System.Collections.Generic;

using Nereal.Serialization;

namespace Ragima {
    /// <summary>
    /// Тип цели: объединение нескольких целей.
    /// </summary>
    public class UnionTarget : TargetType {
        private List<UnionTargetItem> _items;

        public UnionTarget(Languages.Phrase notice) : base(notice) {
            _items = new List<UnionTargetItem>();
        }
        public UnionTarget(Languages.Phrase notice, params TargetType[] targets) : this(notice) {
            foreach (var target in targets)
                AddTarget(target);
        }

        public void AddTarget(TargetType target) {
            _items.Add(new UnionTargetItem(target));
        }

        public override bool IsRealTarget {
            get {
                foreach (var item in _items)
                    if (item.Target.IsRealTarget)
                        return true;
                return false;
            }
        }

        public override void Initialize(TargetRequest request) {
            base.Initialize(request);
            foreach (var item in _items)
                item.Initialize(request);
        }

        public override int GetCount(AbstractObject caster) {
            int count = 0;
            foreach (var item in _items)
                count += item.Target.GetCount(caster);
            return count;
        }

        public override IEnumerable<Region> GetRegions() {
            foreach (var item in _items)
                foreach (var region in item.Target.GetRegions()) {
                    item.AddRegion(region);
                    yield return region;
                }
        }

        public override void ClickRegion(Region region) {
            var item = FindByRegion(region);
            if (item != null)
                item.Target.ClickRegion(region);
        }

        public override bool AcceptRegion(Region region) {
            foreach (var item in _items)
                if (item.Target.AcceptRegion(region)) {
                    item.AddRegion(region);
                    return true;
                }
            return false;
        }

        public override void ClickAcceptedRegion(Region region) {
            var item = FindByRegion(region);
            if (item != null)
                item.Target.ClickAcceptedRegion(region);
        }

        public override TargetArgs GetArgs(Region region) {
            var item = FindByRegion(region);
            return item != null ? new UnionTargetArgs(Request.Player, Request.Caster, new UnionData(item.Target.GetArgs(region))) : base.GetArgs(region);
        }

        private UnionTargetItem FindByRegion(Region region) {
            foreach (var item in _items)
                if (item.ExistsRegion(region))
                    return item;
            return null;
        }

        private class UnionTargetItem {
            public readonly TargetType Target;
            private List<Region> _regions;

            public UnionTargetItem(TargetType target) {
                Target = target;
                _regions = new List<Region>();
            }

            public void Initialize(TargetRequest request) {
                _regions.Clear();
                Target.Initialize(request);
            }

            public void AddRegion(Region region) {
                if (!_regions.Contains(region))
                    _regions.Add(region);
            }
            public bool ExistsRegion(Region region) {
                return _regions.Contains(region);
            }
        }
    }

    [TypeId("union")]
    public class UnionTargetArgs : TargetArgs<UnionData> {
        [Serialize, XmlName("target")]
        private UnionData _target;

        public UnionTargetArgs() {
        }
        public UnionTargetArgs(Player player, AbstractObject caster, UnionData target) : base(player, caster) {
            _target = target;
        }

        public override UnionData Target {
            get { return _target; }
        }
    }

    public struct UnionData {
        [XmlName("args")]
        public TargetArgs Args;

        public UnionData(TargetArgs args) {
            Args = args;
        }

        public bool GetArgs<T1>(out TargetArgs<T1> args1) {
            args1 = Args as TargetArgs<T1>;
            return args1 != null;
        }

        public int GetArgs<T1, T2>(out TargetArgs<T1> args1, out TargetArgs<T2> args2) {
            args1 = Args as TargetArgs<T1>;
            args2 = Args as TargetArgs<T2>;
            if (args1 != null)
                return 1;
            if (args2 != null)
                return 2;
            return 0;
        }
    }
}
